// Copyright DustedPixels.com 2008. All rights reserved.

package com.dustedpixels.jasmin.unit;


/**
 * @author micapolos@gmail.com (Michal Pociecha-Los)
 */
public final class ProcessBenchmark {
  private final static int CYCLES = 3500000 * 4;
  
  public static void main(String[] args) {
    test(new IncProcess1());
    test(new IncProcess1CacheLocal());
    test(new IncProcess2());
    test(new IncProcess4());
    test(new AddProcess1());
    test(new AddProcess2());
    test(new AddProcess4());
    test(new AddProcess4LocalCache());
    test(new CacheGlobal());
    test(new CacheLocal());
  }

  public static void test(Process process) {
    process.run(CYCLES);
    long time = System.currentTimeMillis();
    process.run(CYCLES);
    System.out.println(process + ": " + (System.currentTimeMillis() - time) + "ms");
  }
  
  private static final class IncProcess1 implements Process {
    private long counter;
    public void run(int millis) {
      while (millis-- != 0) {
        counter++;
      }
    }    
  }

  private static final class IncProcess1CacheLocal implements Process {
    private long counter;
    public void run(int millis) {
      long counter = this.counter;
      while (millis-- != 0) {
        counter++;
      }
      this.counter = counter;
    }    
  }

  private static final class IncProcess2 implements Process {
    private long counter;
    public void run(int millis) {
      while (millis-- != 0) {
        counter++;
        counter++;
      }
    }    
  }

  private static final class IncProcess4 implements Process {
    private long counter;
    public void run(int millis) {
      while (millis-- != 0) {
        counter++;
        counter++;
        counter++;
        counter++;
      }
    }    
  }

  private static final class AddProcess1 implements Process {
    private long counter = 1;
    public void run(int millis) {
      while (millis-- != 0) {
        counter += counter;
      }
    }    
  }
  
  private static final class AddProcess2 implements Process {
    private long counter = 1;
    public void run(int millis) {
      while (millis-- != 0) {
        counter += counter;
        counter += counter;
      }
    }    
  }
  
  private static final class AddProcess4 implements Process {
    private long counter = 1;
    public void run(int millis) {
      while (millis-- != 0) {
        counter += counter;
        counter += counter;
        counter += counter;
        counter += counter;
      }
    }    
  }

  private static final class AddProcess4LocalCache implements Process {
    private long counter = 1;
    public void run(int millis) {
      long counter = this.counter;
      while (millis-- != 0) {
        counter += counter;
        counter += counter;
        counter += counter;
        counter += counter;
      }
      this.counter = counter;
    }    
  }

  private static final class CacheGlobal implements Process {
    private long counter = 1;
    private long counter2 = 2;
    private long counter3 = 3;
    private boolean clock = false;
    public void run(int millis) {
      while (millis-- != 0) {
        clock = !clock;
        if (clock) {
          counter3 = counter + counter3;
          counter2 += counter + counter2;
          counter += counter2;
        } else {
          counter += counter2;
          counter2 += counter + counter2;
          counter3 = counter + counter2;
        }
      }
    }    
  }

  private static final class CacheLocal implements Process {
    private long counter = 1;
    private long counter2 = 2;
    private long counter3 = 3;
    private boolean clock = false;
    public void run(int millis) {
      long counter = this.counter;
      long counter2 = this.counter2;
      long counter3 = this.counter3;
      boolean clock = this.clock;
      while (millis-- != 0) {
        clock = !clock;
        if (clock) {
          counter3 = counter + counter3;
          counter2 += counter + counter2;
          counter += counter2;
        } else {
          counter += counter2;
          counter2 += counter + counter2;
          counter3 = counter + counter2;
        }
      }
      this.counter = counter;
      this.counter2 = counter2;
      this.counter3 = counter3;
      this.clock = clock;
    }    
  }
}

